Calendars "A word fitly spoken is like apples of gold in pictures of silver" Proverbs 25.11 Introduction The GOLDCAL unit contains Gold's calendaring support. With one simple call to RunCalendar, you can add calendars to your application. By default, Gold will display a single month-at-a-glance calendar (see figure 7-1). The fussy developers (e.g. Oregon inhabitants) can customize the calendar to meet their specific needs. For example, the calendar can be displayed within a larger window. If you are not familiar with Julian dates, you should consider reading the introduction to Chapter 19. Figure 7.1 A Month-at-a-Glance Calendar Activating a Calendar Window To display a (modal) calendar in a pop-up window use the RunCalendar command which is defined as follows: RunCalendar(StartDate:Dates;Tit:string):dates; Displays a month-at-a-glance calendar in a pop-up window. The first parameter is the Julian date of any day in the month which is to be displayed. The second argument is the window title. The function returns the day that was highlighted when the window was closed, or zero if the user presses Esc or clicks on the close icon. If you want to display a fully functional calendar but don't want to have a specific day highlighted, set the boolean variable CalVars.ChooseDay to false. Run the demo DEMCAL1.PAS to display a month-at-a-glance calendar. Customizing the Calendar Icons and Keystrokes A user can easily change months and years by clicking on the 4 navigation icons. You can change the appearance of the icons by modifying the following four character variables defined in CalVars: CalVars.NextMchar - icon to move to next month CalVars.PrevMchar - icon to move to previous month CalVars.NextYchar - icon to move to next year CalVars.PrevYchar - icon to move to previous year The corresponding keystrokes to change months and years are: PgDn and PgUp to change months, Ctrl-PgDn and Ctrl-PgUp to change years. These too can be customized by changing the following word variables defined in CalVars: CalVars.NextMkey CalVars.PrevMkey CalVars.NextYkey CalVars.PrevYkey International users can modify the two character day strings by editing the variable CalVars.DayLetters which is defined as follows: CalVars.DayLetters := 'SuMoTuWeThFrSa'; Controlling the Calendar Colors You can customize the calendar display colors by modifying the following elements of TINT using the function GoldSetColor: CalBorder CalTitle CalIcons CalActiveMonth CalEdgeMonth CalToday CalHiDay The following code is an extract from DEMCAL2.PAS which customizes the calendar colors: procedure CustomizeColors; {} begin GoldSetColor(CalBorder,WhiteOnMagenta); GoldSetColor(CalIcons,GreenOnMagenta); GoldSetColor(CalTitle,YellowOnMagenta); GoldSetColor(CalActiveMonth,YellowOnMagenta); GoldSetColor(CalEdgeMonth,LightgrayOnMagenta); GoldSetColor(CalToday,GreenOnMagenta); GoldSetColor(CalHiday,LightMagentaOnBlack); end; { CustomizeColors } The color used to display each day individually can be customized using a calendar hook. This very flexible technique is discussed later in the chapter. Drawing a Plain Calendar One of the core routines used by the RunCalendar function is DrawMonth, which draws a plain calendar without the icons. If you want to draw a calendar for informational purposes, i.e. with no input support, you can use DrawMonth, which is defined as follows: DrawMonth(Mon,Yr:word;X1,Y1:byte;Active:boolean):Dates; The first two word parameters identify the month and year which is to be displayed. The next two byte parameters indicate the position of the top left of the calendar. The final parameter indicates whether the calendar should be drawn using the active months colors, or the edge month colors. The function returns the Julian date of the top left day in the seven by six day matrix. DrawMonth is used in the demo file DEMCAL7.PAS. Customizing the Window Size By default, the window size is designed to be just large enough to accommodate the monthly calendar. The window size, however, can be made larger so that additional information may be written to the window; such as a daily event log or a To Do list. To change the window size, modify the following CalVars variables before calling RunCalendar: CalVars.WX1, CalVars.WY1, CalVars.WX2, CalVars.WY2. These four variables define the total dimensions of the calendar window. The position of the top left corner of the calendar relative to the window is defined in the following two variables: CalVars.CX1 and CalVars.CY1. Listed below is an extract from DEMCAL3.PAS which shows how the window size and position can be customized: with CALVars do begin WX1 := 10; WY1 := 5; WX2 := 70; WY2 := 20; CX1 := 36; CY1 := 1; end; MouseShow(true); Answer := RunCalendar(TodayInJul,'A Big Calendar'); Using Calendar Hooks The RunCalendar function is designed to be easy to use, but very flexible and customizable. The majority of the flexibility is implemented in calendar hooks. There are three main hooks: a character hook, a color hook and a change hook. If you are not familiar with the principle of hooks in Gold, refer to the section Understanding Hooks in Chapter 3. By using a combination of these hooks, you can create sophisticated calendaring applications. The Character Hook A character hook is a procedure which is called every time a key is pressed or a mouse button is clicked. The hooked procedure is called before the key is processed, i.e. before the character is passed to RunCalendar for processing. The hook is particularly useful for trapping special keys like F1 for help or Alt-N to pop-up a set of notes. All you have to do is create a procedure following some specific rules, and then call the AssignCalCharHook procedure to instruct Gold to call your procedure every time a key is pressed. For a procedure to be eligible as a character hook it must adhere to the following rules: The procedure must be declared as a far procedure at the root level. Refer to the section Understanding Hooks in Chapter 3 for further information. The procedure must be declared with one variable parameter of type word, and two variable parameters of type byte. These parameters identify the user input, i.e. the Key, X and Y. The following procedure declaration follows these rules: {$F+} procedure MyCalendarHook(var Code:word;var X,Y:byte); begin {some code} end; {MyCalendarHook} {$F-} The following procedure is then called to instruct Gold to call your procedure after each calendar input: AssignCalCharHook(Hook:KeyPressedHook); Instructs Gold to call the specified procedure before processing each user input to the calendar window. If subsequently, you want to remove the character hook, execute the command RemoveCalCharHook. Run the demo programs DEMCAL4.PAS and DEMCAL6.PAS to see the character hook in action. The Color Hook The calendar color hook allows a program to customize the display color of each day display on the calendar. Using this feature an application might, for example, displays days with appointments in one color and vacation days in another color. All you have to do is create a procedure following some specific rules, and then call the AssignCalColorHook procedure to instruct Gold to call your procedure every time a day is about to be written to the window. For a procedure to be eligible as a color hook it must adhere to the following rules: The procedure must be declared as a far procedure at the root level. Refer to the section Understanding Hooks in Chapter 3 for further information. The procedure must be declared with one parameter of type Dates, and one variable parameter of type byte. These parameters identify the Julian date of the day to be drawn, and the color which will be used to draw the day. The last parameter, TheCol, is passed to the procedure with the value that would be used if the hook were not in place. The following procedure declaration follows these rules: {$F+} procedure ChangeFriSatSun(TheDay:Dates; var TheCol:byte); {} var DOW: byte; begin if TheCol = Tint[CalActiveMonth] then begin DOW := DOWJul(TheDay); case DOW of 5: TheCol := LightGreenOnBlue; 0,6: TheCol := GreenOnBlue; end; end; end; { ChangeFriSatSun } {$F-} The following procedure is then called to instruct Gold to call your procedure after each calendar input: AssignCalColorHook(Hook:CalColorProc); Instructs Gold to call the specified procedure to determine the color used to draw the day numbers in the calendar grille. If subsequently, you want to remove the color hook, execute the command RemoveCalColorHook. Run the demo programs DEMCAL5.PAS to see the color hook in action. The Change Hook The calendar change hook is designed for sophisticated applications which want to update other parts of the display when the user changes the active day or month on the calendar. For example, a change hook could be used to display a list of the selected day's appointments to the left of the calendar. All you have to do is create a procedure following some specific rules, and then call the AssignCalChangeHook procedure to instruct Gold to call your procedure every time a day is about to be written to the window. For a procedure to be eligible as a change hook it must adhere to the following rules: The procedure must be declared as a far procedure at the root level. Refer to the section Understanding Hooks in Chapter 3 for further information. The procedure must be declared with one parameter of type gCalChange, and two parameters of type longint. The first parameter indicates the type of change that is about to occur. The other two parameters represent dates; the specific date is dependent upon the type of change. The following procedure declaration follows these rules: {$F+} procedure ChangeHook(CType:gCalChange;Val1,Val2:dates); {} begin if CType = ChangeDay then begin SelectedDay := Val2; ActivateBackground; WriteCenter(21,0, PadCenter(FancyDateStr(val2,true,true), 40,' ')); ActivateTopWindow; WinDrawAll; end; end; { ChangeHook } {$F-} The following procedure is then called to instruct Gold to call your procedure after each calendar input: AssignCalChangeHook(Hook:CalChangeProc); Instructs Gold to call the specified procedure every time the active month or day is changed, and when the window is repainted. If subsequently, you want to remove the color hook, execute the command RemoveCalColorHook. Understanding the Passed Parameters There are three different occasions when a change hook is called: when the calendar window is repainted, when the visible month is changed, and when the selected day is changed. The first parameter passed to the hook procedure indicates which hook event is occurring and is of type gCalChange. The enumerated type gCalChange is declared in GOLDCAL as follows: gCalChange = (Paint,ChangeDay,ChangeMonth); The meaning of the two Dates parameters is dependent upon the value of the first parameter as follows: Paint - The first date is the active month and the second date is the active year, e.g. 8 and 1995. ChangeDay - The first date is the old selected date and the second parameter is the date which is about to become selected. Both values represent the Julian date, e.g. 2449583 and 2449584. ChangeMonth - The first date is the active month and the second date is the active year, e.g. 7 and 1996. The majority of applications will only use the ChangeDay function, since this hook is called whenever the active day, month or year is changed. Respond to the paint hook when an application uses an enlarged window to write additional information (e.g. daily appointments) to the non-calendar parts of the window. The contents of the window should be refreshed when the paint message is received. Run the demo programs DEMCAL6.PAS to see the change hook in action. Error Handling Since the calendar is displayed in a window, there is the potential for an Out of Memory error. After calling RunCalendar, be sure to call the function LastCalError to see if the calendar was successfully displayed.